home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 April: Mac OS SDK / Dev.CD Apr 00 SDK1.toast / Development Kits / Mac OS / Apple Guide / Engineering / Context Check Modules / Standard CC Modules / System Context / System.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-02  |  15.5 KB  |  657 lines  |  [TEXT/MPS ]

  1. //    Copyright:    © 1993 Apple Computer, Inc. All rights reserved.
  2. //    Author:        Scott Searle (original)
  3. //                Victor J. Hnyp (extensions)
  4. //                Dave Lyons (misc maintenance)
  5. //    Date:        13-Jan-94
  6.  
  7. // Revisions
  8. //
  9. //    05/01/94    JJ    3.03    use str255 parameter to open Users & Groups Data File
  10. //    01/16/94    GB    3.02    dont call GetMainDevice on non-CQD machines
  11. //  01/13/94    DAL    3.01    •Conditioned out DoGestaltCheck, since the one here never gets called.
  12. //                            UContext.cp short-circuits it and does the work itself.
  13. //                            •Changed LoWord() to (short) in DoHWBitDepthCheck (per Dec 93 code review).
  14. //                            •Changed DoMenuCheck to reflect that items past the first 32 are always
  15. //                            enabled (per Dec 93 code review).
  16. //                            •Fixed DoNumMonitorsCheck to use toolbox calls where available and only
  17. //                            count -active- screen devices (per Dec 93 code review).
  18. //
  19. //  ------------------------------------------------------------------------------------------------------
  20. //
  21. //    03/24/93    VJH    2.06    Fixed:    DoGestaltCheck (again!)
  22. //
  23. //    03/13/93    VJH    2.05    Fixed:    isGuestAccess (again!)
  24. //
  25. //    03/11/93    VJH    2.04    Fixed:    isGuestAccess, returned isVideoHWBitDepth to original design
  26. //
  27. //    02/08/93    VJH    2.03    Fixed:    DoGestaltCheck, DoNameCheck, DoHWBitDepthCheck and DoNumMonitorsCheck
  28. //
  29. //    01/18/93    VJH    2.02    Fixed:    Gestalt and menu checks
  30.  
  31. #pragma    load "AllHeaders.dump"
  32.  
  33. #include "Utility.h"
  34. #include "Proto.h"
  35. #include "Context.h"
  36. #include "System.h"
  37.  
  38. #define    kComputerNameStrID        (-16413)
  39.  
  40. /* ------------------ Forward Declaration ---------------- */
  41. #if 0
  42.     pascal Boolean DoGestaltCheck(GestaltStatePtr msg);
  43. #endif
  44. pascal Boolean DoMenuCheck(MenuIsAvailablePtr msg);
  45. pascal Boolean DoMonitorBitDepthCheck(BitDepthStatePtr msg);
  46. pascal Boolean DoNameCheck(ComputerNameInfoPtr msg);
  47. pascal Boolean DoHWBitDepthCheck(BitDepthStatePtr msg);
  48. pascal Boolean DoNumMonitorsCheck(BitDepthStatePtr msg);
  49. pascal Boolean DoFileSharingState(FileSharingPtr msg);
  50. pascal Boolean DoGuestAccessCheck(FileSharingPtr msg);
  51. MenuHandle GetIndexedMenuHandle(short index);
  52. void GetMenuTitle(MenuHandle menu, unsigned char* name);
  53. OSErr    FindSysFolder(short *foundVRefNum, long *foundDirID);
  54.  
  55.  
  56. pascal OSErr main(ContextSelectorPtr msg, Size inSize,
  57.                     void* outMessage, Size* outSize, Handle /*startGlobals*/)
  58. {
  59.     Boolean        ret    =    false;
  60.     OSErr        err    =    errAECorruptData;
  61.     
  62.     if(inSize < sizeof(ContextSelector))                    /* If inSize is < length of selector (a long), */
  63.         return(err);                                        /* return an error. Would be nice to have a specific error # */
  64.     
  65.     switch (msg->selector)
  66.     {
  67.         // Never gets called--see UContext.cp (13-Jan-94 DAL)
  68.         #if 0
  69.             case gestaltCheck:
  70.                 ret = DoGestaltCheck((GestaltStatePtr)msg);
  71.                 break;
  72.         #endif
  73.  
  74.         case menuItemExists:
  75.         case menuItemMarked:
  76.         case menuItemEnabled:
  77.         case menuItemDisabled:
  78.             ret = DoMenuCheck((MenuIsAvailablePtr)msg);
  79.             break;
  80.             
  81.         case isFileSharing :
  82.             ret = DoFileSharingState((FileSharingPtr)msg);
  83.             break;
  84.             
  85.         case isVideoHWBitDepth :
  86.             ret = DoHWBitDepthCheck((BitDepthStatePtr)msg);
  87.             break;
  88.  
  89.         case isMonitorBitDepth :
  90.             ret = DoMonitorBitDepthCheck((BitDepthStatePtr)msg);
  91.             break;
  92.             
  93.         case isComputerNamed :
  94.             ret = DoNameCheck((ComputerNameInfoPtr)msg);
  95.             break;
  96.             
  97.         case isGuestAccess :
  98.             ret = DoGuestAccessCheck((FileSharingPtr)msg);
  99.             break;
  100.             
  101.         case isNumberMonitors :
  102.             ret = DoNumMonitorsCheck((BitDepthStatePtr)msg);
  103.             break;
  104.             
  105.         default:                                            /* None of the pre-defined types. Exit with error */
  106.             break;                                            /* Would be nice to have a specific error # */
  107.     }
  108.  
  109.     err    = SetContextResult(&ret, sizeof(Boolean), outMessage, outSize);
  110.     return(err);
  111. }
  112.  
  113.  
  114. // Never gets called--see UContext.cp (13-Jan-94 DAL)
  115. #if 0
  116.     pascal Boolean DoGestaltCheck(GestaltStatePtr msg)
  117.     {
  118.         long            result;
  119.         Boolean            ret    =    false;
  120.         OSErr            err    =    errAECorruptData;
  121.     
  122.         if (err = Gestalt(msg->gestaltSelector, &result) == noErr)
  123.         {
  124.             switch (msg->compareSelector)
  125.             {
  126.                 case equals:
  127.                     ret = result == msg->value;
  128.                     break;
  129.                 case notEqualTo:
  130.                     ret = result != msg->value;
  131.                     break;
  132.                 case greaterThan:
  133.                     ret = result > msg->value;
  134.                     break;
  135.                 case lessThan:
  136.                     ret = result < msg->value;
  137.                     break;
  138.                 case greaterThanOrEqualTo:
  139.                     ret = result >= msg->value;
  140.                     break;
  141.                 case lessThanOrEqualTo:
  142.                     ret = result <= msg->value;
  143.                     break;
  144.                 default:
  145.                     break;
  146.             }
  147.         }
  148.         
  149.         return(ret);
  150.     }
  151. #endif
  152.  
  153.  
  154. pascal Boolean DoMonitorBitDepthCheck(BitDepthStatePtr msg)
  155. {
  156.     Boolean            ret    = false;
  157.     GDHandle        theGD;
  158.     short            pixelDepth;
  159.     SysEnvRec        sysEnv;
  160.     
  161.     SysEnvirons( curSysEnvVers, &sysEnv );
  162.     if(sysEnv.hasColorQD) {
  163.         theGD = GetMainDevice();                    // Can't do this on non-CQD machines
  164.         pixelDepth = (**(**theGD).gdPMap).pixelSize;
  165.     } else
  166.         pixelDepth = 1;
  167.     
  168.     switch (msg->compareSelector)
  169.     {
  170.         case equals:
  171.             ret = pixelDepth == msg->compareValue;
  172.             break;
  173.         case notEqualTo:
  174.             ret = pixelDepth != msg->compareValue;
  175.             break;
  176.         case greaterThan:
  177.             ret = pixelDepth > msg->compareValue;
  178.             break;
  179.         case lessThan:
  180.             ret = pixelDepth < msg->compareValue;
  181.             break;
  182.         case greaterThanOrEqualTo:
  183.             ret = pixelDepth >= msg->compareValue;
  184.             break;
  185.         case lessThanOrEqualTo:
  186.             ret = pixelDepth <= msg->compareValue;
  187.             break;
  188.         default:
  189.             break;
  190.     }
  191.     return(ret);
  192. } // DoMonitorBitDepthCheck
  193.  
  194.  
  195. pascal Boolean DoNameCheck(ComputerNameInfoPtr msg)
  196. {
  197.     Str255            name;
  198.     Boolean            ret    =    false;
  199.     OSErr            err    =    noErr;
  200.  
  201.     if ((err = GetTheString(kComputerNameStrID, name)) == noErr)
  202.     {
  203.         ret    = CompareStringSpec(name, &msg->computerName);
  204.     }
  205.  
  206.     return(ret);
  207. } // DoNameCheck
  208.  
  209.  
  210. // 13-Jan-94 DAL -- This logic seems dubious to me.  It's all based on the main monitor.
  211. // Maybe it would be better if equal/not-equal checked whether *any* monitor had the
  212. // target bit depth, and >/>= checked whether the deepest monitor has -at least- the target
  213. // bit depth, and </<= checked whether the shallowest monitor had less than the target bit
  214. // depth.
  215.  
  216. pascal Boolean DoHWBitDepthCheck(BitDepthStatePtr msg)
  217. {
  218.     Boolean            ret    =    false;
  219.     GDHandle        theGD;
  220.     short            bitDepth;
  221.     short            mode;
  222.     SysEnvRec        sysEnv;
  223.     
  224.     SysEnvirons( curSysEnvVers, &sysEnv );
  225.     if(!sysEnv.hasColorQD)
  226.         {
  227.         return(DoMonitorBitDepthCheck(msg));        // only has 1 bit depth on this non-CQD machine, so we don't need to do the HasDepth calls below
  228.         }
  229.     
  230.     theGD = GetMainDevice();                        // dont do this in non-CQD machines
  231.     bitDepth = (short)( msg->compareValue );
  232.     mode = HasDepth(theGD, bitDepth, 1, 1);
  233.  
  234.     switch (msg->compareSelector)
  235.     {
  236.         case equals:
  237.             if( mode )
  238.                 ret = true;
  239.             break;
  240.         case notEqualTo:
  241.             if( ! mode )
  242.                 ret = true;
  243.             break;
  244.         case greaterThan:
  245.             bitDepth = bitDepth << 1;
  246.             mode = HasDepth(theGD, bitDepth, 1, 1);
  247.             if( mode )
  248.                 ret = true;
  249.             break;
  250.         case lessThan:
  251.             bitDepth = bitDepth >> 1;
  252.             mode = HasDepth(theGD, bitDepth, 1, 1);
  253.             if( mode )
  254.                 ret = true;
  255.             break;
  256.         case greaterThanOrEqualTo:
  257.             if( mode )
  258.                 ret = true;
  259.             else
  260.             {
  261.                 bitDepth = bitDepth << 1;
  262.                 mode = HasDepth(theGD, bitDepth, 1, 1);
  263.                 if( mode )
  264.                     ret = true;
  265.             }
  266.             break;
  267.         case lessThanOrEqualTo:
  268.             if( mode )
  269.                 ret = true;
  270.             else
  271.             {
  272.                 bitDepth = bitDepth >> 1;
  273.                 mode = HasDepth(theGD, bitDepth, 1, 1);
  274.                 if( mode )
  275.                     ret = true;
  276.             }
  277.             break;
  278.         default:
  279.             break;
  280.     }
  281.     
  282.     return(ret);
  283. } // DoHWBitDepthCheck
  284.  
  285.  
  286. pascal Boolean DoNumMonitorsCheck(BitDepthStatePtr msg)
  287. {
  288.     Boolean            ret    =    false;
  289.     GDHandle        theGD;
  290.     short            numMonitors = 0;
  291.     SysEnvRec        sysEnv;
  292.     
  293.     // fix the nonCQD crash
  294.     SysEnvirons( curSysEnvVers, &sysEnv );
  295.     if(sysEnv.hasColorQD) {
  296.         theGD = GetDeviceList();                    // Can't do this on non-CQD machines
  297.         
  298.         while( theGD ) {
  299.             if( TestDeviceAttribute(theGD, screenDevice) && TestDeviceAttribute(theGD, screenActive) )
  300.                 numMonitors++;
  301.                 
  302.             theGD = GetNextDevice(theGD);            
  303.         }
  304.     } else
  305.         numMonitors = 1;
  306.         
  307. #if 0                
  308.     theGD = GetDeviceList();
  309.     
  310.     while( theGD ) {
  311.         if( TestDeviceAttribute(theGD, screenDevice) && TestDeviceAttribute(theGD, screenActive) )
  312.             numMonitors++;
  313.  
  314.         theGD = GetNextDevice(theGD);            
  315.     }
  316. #endif
  317.  
  318.     switch (msg->compareSelector)
  319.     {
  320.         case equals:
  321.             ret = numMonitors == msg->compareValue;
  322.             break;
  323.         case notEqualTo:
  324.             ret = numMonitors != msg->compareValue;
  325.             break;
  326.         case greaterThan:
  327.             ret = numMonitors > msg->compareValue;
  328.             break;
  329.         case lessThan:
  330.             ret = numMonitors < msg->compareValue;
  331.             break;
  332.         case greaterThanOrEqualTo:
  333.             ret = numMonitors >= msg->compareValue;
  334.             break;
  335.         case lessThanOrEqualTo:
  336.             ret = numMonitors <= msg->compareValue;
  337.             break;
  338.         default:
  339.             break;
  340.     }
  341.     return(ret);
  342. } // DoNumMonitorsCheck
  343.  
  344.  
  345. pascal Boolean DoMenuCheck(MenuIsAvailablePtr msg)
  346. {
  347.     MenuHandle        menu;
  348.     Str255            menuTitle;
  349.     Str255            menuItem;
  350.     short            i, j;
  351.     short            numItems;
  352.     short            mark;
  353.     unsigned long    enableFlags;
  354.     unsigned long    mask;
  355.     unsigned long    result;
  356.     short            theItem    =    0;
  357.     MenuHandle        theMenu    =    nil;
  358.     Boolean            ret        =    false;
  359.     Boolean            foundIt    =    false;
  360.     
  361.     StringSpecPtr    secondSP;                    // Need to get around record structure limitation
  362.  
  363.     secondSP = (StringSpecPtr)GetNextItemAddress( &msg->menuTitle.str );
  364.  
  365. // addresses
  366. // DebugStr( (char*)N2S( &msg->mSelector ));
  367. // values
  368. // DebugStr( (char*)N2S( msg->mSelector ));
  369.  
  370.     for (i = 0; !foundIt && (menu = GetIndexedMenuHandle(i)); ++i)
  371.     {
  372.         GetMenuTitle(menu, menuTitle);
  373.  
  374.         if (CompareStringSpec(menuTitle, &msg->menuTitle))
  375.             for (j = 1, numItems = CountMItems(menu); j <= numItems; ++j)
  376.             {
  377.                 GetItem(menu, j, menuItem);
  378.  
  379.                 if (CompareStringSpec(menuItem, secondSP))
  380.                 {
  381.                     theMenu = menu;
  382.                     theItem = j;
  383.                     foundIt = true;
  384.                     break;
  385.                 }
  386.             }
  387.     }
  388.  
  389.     if (foundIt && theMenu && theItem)
  390.     {
  391.         switch (msg->mSelector)
  392.         {
  393.             case    menuItemExists:
  394.                 ret = foundIt;
  395.                 break;
  396.  
  397.             case    menuItemMarked:
  398.                 GetItemMark(theMenu, theItem, &mark);
  399.                 ret = (mark != 0);
  400.                 break;
  401.  
  402.             case    menuItemEnabled:
  403.             case    menuItemDisabled:
  404.                 if(theItem > 32)
  405.                 {
  406.                     result = 1;        // Items beyond the 1st 32 are always enabled
  407.                 }
  408.                 else
  409.                 {
  410.                     enableFlags    =    (unsigned long) (**theMenu).enableFlags;
  411.                     mask        =    (unsigned long) ((unsigned long) 1 << (theItem - 1));
  412.                     result        =    (unsigned long) (enableFlags & mask);
  413.                 }
  414.                 ret = (msg->mSelector == menuItemEnabled) ?
  415.                         result != (unsigned long) 0 :
  416.                         result == (unsigned long) 0;
  417.                 break;
  418.         }
  419.     }
  420.  
  421.     return(ret);
  422. } // DoMenuCheck
  423.  
  424.  
  425.  
  426. pascal Boolean VolIsSharable(short vRefNum)
  427. // See if local File Sharing is enabled on the volume specified by vRefNum
  428. {
  429.     HIOParam                pb;
  430.     GetVolParmsInfoBuffer    infoBuffer;
  431.     OSErr                    err;
  432.     Boolean                    ret = false;
  433.     char                    nameString[32];
  434.  
  435.     pb.ioNamePtr = nil;
  436.     pb.ioVRefNum = vRefNum;
  437.     pb.ioBuffer = (Ptr)&infoBuffer;
  438.     pb.ioReqCount = sizeof(infoBuffer);
  439.     pb.ioNamePtr = nameString;
  440.  
  441.     err = PBHGetVolParmsSync((HParmBlkPtr)&pb);
  442.     if(err == noErr)
  443.         if(infoBuffer.vMAttrib & 0x0100 )                // bit 8 = bHasPersonalAccessPrivileges flag
  444.             ret = true;
  445.  
  446.     return( ret );
  447. } // VolIsSharable;
  448.  
  449.  
  450.  
  451. pascal Boolean DoFileSharingState(FileSharingPtr msg)
  452. //See if File Sharing is turned on by seeing if any volume has
  453. //local File Sharing enabled
  454. {
  455.     HVolumeParam            pb;
  456.     OSErr                    err            = noErr;
  457.     short                    volIndex    = 1;
  458.     Boolean                    sharing        = false;
  459.     Boolean                    ret            = false;
  460.     char                    nameString[32];
  461.  
  462.     do
  463.     {
  464.         pb.ioNamePtr = nil;
  465.         pb.ioVolIndex = volIndex;
  466.         pb.ioNamePtr = nameString;
  467.  
  468.         err = PBHGetVInfoSync((HParmBlkPtr)&pb);
  469.         if( err == noErr )
  470.             sharing = VolIsSharable(pb.ioVRefNum);
  471.             
  472.         volIndex += 1;
  473.     }
  474.     while ((err == noErr) &&
  475.     ( !sharing ));                        //stop if error or if a volume has local File Sharing enabled
  476.  
  477.     switch (msg->compareValue)
  478.     {
  479.         case on:
  480.             ret = sharing == true;
  481.             break;
  482.         case off:
  483.             ret = sharing == false;
  484.             break;
  485.         default:
  486.             break;
  487.     }
  488.     
  489.     return( ret );
  490. }
  491.  
  492.  
  493. /*
  494. pascal Boolean DoGuestAccessCheck(FileSharingPtr msg)
  495. //See what priveleges guests have for startup volume when hooking in via Guest Access
  496. {
  497.     OSErr                    err            = noErr;
  498.     Boolean                    ret            = false;
  499.     short                    startupVolRefNum;
  500.     long                    systemDirID;
  501.     HParamBlockRec            thePB;
  502.     AccessParam                *hapb = (AccessParam*)&thePB;
  503.     HFileParam                *hfpb = (HFileParam*)&thePB;
  504.     char                    nameString[32];
  505.     OSErr                    localError;
  506.     short                    thePrivs;
  507.  
  508.     if( FindSysFolder( &startupVolRefNum, &systemDirID ))            // Error getting volume ref num of startup volume
  509.         return( ret );
  510.  
  511.     // Set the param block up for getting information about the startup volume sharing
  512.     thePB.accessParam.ioCompletion = nil;
  513.     thePB.accessParam.ioVRefNum = startupVolRefNum;                    // Use the startup volume reference for lookup
  514.     thePB.fileParam.ioDirID = fsRtDirID;                            // Use the root directory for lookup
  515.     thePB.accessParam.ioNamePtr = nameString;
  516.  
  517.     // Get information on the startup volume SYNCHRONOUSLY, by passing pointer to our param block
  518.     if (localError = PBHGetDirAccess((HParmBlkPtr)&thePB,false))    // Error getting information
  519.         return( ret );
  520.         
  521.     thePrivs = HiWord( thePB.accessParam.ioACAccess );
  522.     
  523.     // Note - We can ignore bit 28 (blank access privileges) for root directories
  524.     
  525.     switch (msg->compareValue)
  526.     {
  527.         case seeFolders:
  528.             ret = thePrivs & 1;
  529.             break;
  530.         case seeFiles:
  531.             ret = thePrivs & 2;
  532.             break;
  533.         case makeChanges:
  534.             ret = thePrivs & 4;
  535.             break;
  536.         default:
  537.             break;
  538.     }
  539.     
  540.     return( ret );
  541. } // DoGuestAccessCheck
  542. */
  543.  
  544.  
  545. pascal Boolean DoGuestAccessCheck(FileSharingPtr msg)
  546. //See if Guest Access is turned on by checking byte within "Users & Groups Data File"
  547. {
  548.     OSErr                    err            = noErr;
  549.     Boolean                    ret            = false;
  550.     short                    startupVolRefNum = 0;
  551.     long                    theDirID    = 0;
  552.     long                    bytesToRead;
  553.     unsigned char            theVal;
  554.     short                    fRefNum;
  555.     
  556.     if( FindFolder( kOnSystemDisk, kPreferencesFolderType, kDontCreateFolder, &startupVolRefNum, &theDirID ))
  557.         return( ret );
  558.         
  559.     if( HOpenDF( startupVolRefNum, theDirID, msg->filename, fsRdPerm, &fRefNum ))
  560.         return( ret );
  561.         
  562.     if( SetFPos( fRefNum, fsFromStart, 0x1B ))            // "Record Number" of machine name
  563.         return( ret );
  564.         
  565.     bytesToRead = 1;
  566.     if( FSRead( fRefNum, &bytesToRead, &theVal ))
  567.         return( ret );
  568.         
  569.     if( SetFPos( fRefNum, fsFromStart, theVal * 0x200 + 0x3C ))        // Byte of guest access privileges
  570.         return( ret );
  571.  
  572.     bytesToRead = 1;
  573.     if( FSRead( fRefNum, &bytesToRead, &theVal ))
  574.         return( ret );
  575.         
  576.     if( FSClose( fRefNum ))
  577.         return( ret );
  578.         
  579.     switch (msg->compareValue)
  580.     {
  581.         case on:
  582.             if( !( theVal & 2 ))
  583.                 ret = true;
  584.             break;
  585.         case off:
  586.             if( theVal & 2 )
  587.                 ret = true;
  588.             break;
  589.         default:
  590.             break;
  591.     }
  592.     
  593.     return( ret );
  594. } // DoGuestAccessCheck
  595.  
  596.  
  597.  
  598. MenuHandle GetIndexedMenuHandle(short index)
  599. {
  600.     short                numMenus;
  601.     MenuRecPtr            menuRecList;
  602.     MenuListRecHdl        mList    =    (MenuListRecHdl)MenuList;
  603.     MenuHandle            menu    =    nil;
  604.  
  605.     if (mList)
  606.     {
  607.         numMenus        =    (**mList).lastMenu / sizeof(MenuRec);
  608.         menuRecList    =    (MenuRecPtr)&(**mList).startMenuRecList;
  609.  
  610.         if (index >= 0 && index < numMenus)
  611.             menu = menuRecList[index].menuHdl;
  612.     }
  613.  
  614.     return(menu);
  615. } // GetIndexedMenuHandle
  616.  
  617.  
  618.  
  619. void GetMenuTitle(MenuHandle menu, unsigned char* name)
  620. {
  621.     BlockMove(&(**menu).menuData, name, (long)((**menu).menuData[0] + 1));
  622. } // GetMenuTitle
  623.  
  624.  
  625.  
  626. OSErr    FindSysFolder(short *foundVRefNum, long *foundDirID)
  627. {
  628.     OSErr            err;
  629.     
  630.     *foundVRefNum = 0;
  631.     *foundDirID = 0;
  632.     err = FindFolder( kOnSystemDisk, kSystemFolderType, kDontCreateFolder, foundVRefNum, foundDirID );
  633.     return( err );
  634. } // FindSysFolder();
  635.  
  636.  
  637.  
  638. OSErr    FindFile(char *filename, short theVolume, long theDirID)
  639. {
  640.     OSErr            err;
  641.     HFileInfo        thePB;
  642.     
  643.     /* Set the param block up for getting information about the given file */
  644.     thePB.ioCompletion = nil;
  645.     thePB.ioNamePtr = filename;                            // File name we want
  646.     thePB.ioVRefNum = theVolume;                        // Volume to be searched
  647.     thePB.ioFDirIndex = 0;                                // Use the filename to find our file
  648.     thePB.ioDirID = theDirID;                            // The directory to be searched
  649.  
  650.     if (err = PBGetCatInfo((CInfoPBPtr)&thePB,false))    // Error getting information
  651.         return( err );
  652.  
  653.     return( 0 );
  654. } // FindFile();
  655.  
  656.  
  657.